/**
 * @fileOverview 通用单级菜单。
 * @version 0.8.0.0
 * @author Direct Guo
 */

/**
 * 单级菜单类
 * @description 1、可以为多行多列多页。
 * @description 2、封装了跳转、翻页、换行等常用菜单行为。
 * @description 3、只能用于一级菜单
 * @class
 * @param {int} w 菜单横向最大条目数，为空则使用默认值5
 * @param {int} h 菜单纵向最大条目数，为空则使用默认值3
 * @param {int} length 菜单的总数量，为空则使用默认值15
 * @property {int} i 当前选中项的序号
 * @property {int} w 菜单横向最大条目数
 * @property {int} h 菜单纵向最大条目数
 * @property {int} length 菜单的总数量
 * @property {boolean} defkey 是否响应默认按键
 * @example

说明：
 1.此类需要jQuery和common.js支持， 请保证html中加载这两项
 2.此菜单只管理菜单行为逻辑，不管理数据和现实逻辑，数据和显示需要根据不同接口或者页面具体编写
 3.具体项目代码请看T12下的 巴巴变相册，其中login和bigphoto是单页菜单、album和photolist 是多页菜单


// = 第一步 =  HTML中引入jquery、common.js、menu_a.js


// = 第二步 =

//定义login对象为一个菜单, 此菜单宽度为1,高度为3,总菜单项为3, 此菜单是一个单页菜单。
//使用jQuery的extend方法，给新建的菜单对象加上特有方法和属性。
var login = $.extend(new Menu_A(1, 3, 3), {
	//定义打开菜单时的操作
    onOpen: function(){
        common.log(this.name + " onOpen!")
		//绘制数据和焦点，具体见下方
        this.drawFocus();
        this.drawData();
		//显示login框
        this.show();
    },
	//定义打开菜单项改变时的操作
    onChange: function(){
        common.log(this.name + " onChange! " + this.i)
		//绘制焦点，见下方
        this.drawFocus();
    },
	//定义进入菜单项时的操作
    onEnter: function(){
        common.log(this.name + " onEnter! " + this.i)
        var self = this;
		//根据进入的项目分开操作
        switch (this.i) {
            case 0:
            case 1:
                //用户名密码输入时
				//...
                break;
            case 2:
                //确定时
				//...
                break;
        }
    },
	//其余事件因为在这个login框中使用不到，所以可以不定义
	
	
	//附加属性和功能，此处为在页面中显示菜单的相关逻辑
	
    dom: null, //存储指向login框DOM的jquery对象
    name: "登陆框", //分辨对象的作用，不是必须
    data: ["gavin2026cn@163.com", "o1nscEN2"], //储存用户名密码
    //显示login框
    show: function(){
        this.dom.show();
    },
    //隐藏login框
    hide: function(){
        this.dom.hide();
    },
	//绘制焦点，给当前选中项加current样式，根据页面结构编写
    drawFocus: function(){
        var items = this.dom.find("li")
        items.filter(".current").removeClass("current");
        items.eq(this.i).addClass("current");
    },
	//绘制数据，此处为用户名密码，根据页面结构编写
    drawData: function(){
        var items = this.dom.find("li")
        items.eq(0).find(".albumsLoginInput").html(this.data[0]);
        items.eq(1).find(".albumsLoginInput").html(this.data[1]);
    },
})

// = 第三步 = 在页面加载结束后，进行初始化

$(function(){
	//启用通用键盘管理
	common.key.init();
	
	//绑定dom
    login.dom = $(".albumsLogin");
	
	//启动login窗口，到此，就可以登陆窗口就可以控制了
    login.open();
    
})

//具体项目代码请看T12下的 巴巴变相册，其中album和photolist 是多页菜单
 */
var Menu_A = function(w, h, length){
    w && (this.w = w);
    h && (this.h = h);
    length && (this.length = length);
}

Menu_A.prototype = {
    /**
     * 检查i必须为正整数,否则返回当前i
     * @private
     * @function
     * @param {int} i 被检查的变量
     * @returns {int} 检查后的数
     */
    checki: function(i){
        return (typeof(i) != "number" || i < 0) ? this.i : Math.floor(i); //无i则返回当前焦点页信息
    },
    /**
     * 将页行列对象形式储存的项目转换为项目序号
     * @private
     * @function
     * @param {object} m 格式为{x:a,y:b,z:c}的对象，其中a为列编号，b为所在页行编号，c为页编号
     * @returns {int} 项目序号
     */
    xyz2i: function(m){
        var x = m.x == null ? 0 : m.x;
        var y = m.y == null ? 0 : m.y;
        var z = m.z == null ? 0 : m.z;
        if (x < 0 || x >= this.w || y < 0 || y >= this.h || z < 0) {
            return false
        }
        return z * this.p() + y * this.w + x;
    },
    /**
     * 将行列对象形式储存的项目转换为项目序号
     * @private
     * @function
     * @param {object} m 格式为{x:a,y:b}的对象，其中a为列编号，b为行编号
     * @returns {int} 项目序号
     */
    xy2i: function(m){
        var x = m.x == null ? 0 : m.x;
        var y = m.y == null ? 0 : m.y;
        if (x < 0 || x >= this.w || y < 0) {
            return false
        }
        return y * this.w + x;
    },
    /**
     * 前后移动当前项
     * @private
     * @function
     * @param {int} i 向前、后移动的幅度，正数为向后移动，负数为向前移动
     * @returns {int} 是否跳转成功
     */
    movex: function(i){
        var next = this.i + i;
        
        //限制
        var max = this.length;
		next = this.rmd(next, max);
        //执行
        return this.go(next);
    },
    /**
     * 纵向移动当前项
     * @private
     * @function
     * @param {int} i 向前、后移动的幅度，正数为向后移动，负数为向前移动
     * @returns {int} 是否跳转成功
     */
    movey: function(i){
        var last = this.i2xy(this.length - 1);
        var next = this.i2xy();
        next.y += i;
        
        //限制
        var max = next.x > last.x ? last.y : last.y + 1;
		next.y = this.rmd(next.y, max);
        
        //执行
        return this.goxy(next);
    },
    /**
     * 翻页
     * @private
     * @function
     * @param {int} i 向前、后翻页的幅度，正数为向后翻页，负数为向前翻页
     * @returns {int} 是否翻页成功
     */
    movez: function(i){
        var last = this.i2xyz(this.length - 1);
        var next = this.i2xyz();
        next.z += i;
        
        //限制
        var max = last.z + 1;
		next.z = this.rmd(next.z, max);
        //如果此页中选中项目超出有效区域
        if (this.xyz2i(next) >= this.length) {
            next = last;
        }
        //执行
        return this.goxyz(next);
    },
	rmd: function(curr, max){
		return (curr >= max || curr < 0) ? (curr + max) % max : curr;
	},
    /**
     * 按键响应函数
     * @private
     * @function
     * @param {int} key 按下的键盘码。
     */
    keyPress: function(key){
        //默认按键响应
        if (this.defkey) {
            switch (key) {
                case keyCodeArr.up:
                    this.h > 1 && this.movey(-1);
                    break;
                case keyCodeArr.down:
                    this.h > 1 && this.movey(1);
                    break;
                case keyCodeArr.left:
                    this.w > 1 && this.movex(-1);
                    break;
                case keyCodeArr.right:
                    this.w > 1 && this.movex(1);
                    break;
                case keyCodeArr.pageUp:
                    this.movez(-1);
                    break;
                case keyCodeArr.pageDn:
                    this.movez(1);
                    break;
                case keyCodeArr.enter:
                    this.enter();
                    break;
            }
        }
        //按键响应事件
        this.onKeyPress && this.onKeyPress(key);
    },
    
    i: 0, 
    w: 3, //菜单项一页行数
    h: 3, //菜单项一页列数
    length: 9, //选项的总条目数
    defkey: true, //是否开启默认按键响应
    
    /**
     * 返回本菜单一页能够容纳的item数
     * @public
     * @function
     * @returns {int} item数
     */
    p: function(){
        return this.w * this.h;
    },
    /**
     * 获取第i项在其所在行的编号。也就是列号。
     * @public
     * @function
     * @param {int} i 第i项，如果不传参数则默认为当前选中项。
     * @returns {int} 列编号
     */
    il: function(i){
        return this.checki(i) % this.w;
    },
    /**
     * 获取第i项在其所在页的编号。
     * @public
     * @function
     * @param {int} i 第i项，如果不传参数则默认为当前选中项。
     * @returns {int} 编号
     */
    ip: function(i){
        return this.checki(i) % this.p();
    },
    /**
     * 获取第i项所在的行编号。
     * @public
     * @function
     * @param {int} i 第i项，如果不传参数则默认为当前选中项。
     * @returns {int} 行编号
     */
    y: function(i){
        return Math.floor(this.checki(i) / this.w);
    },
    /**
     * 获取第i项在其所在页的行编号。
     * @public
     * @function
     * @param {int} i 第i项，如果不传参数则默认为当前选中项。
     * @returns {int} 所在页的行编号
     */
    yp: function(i){
        return Math.floor(this.checki(i) / this.w) % this.h;
    },
    /**
     * 获取第i项所在的页编号。
     * @public
     * @function
     * @param {int} i 第i项，如果不传参数则默认为当前选中项。
     * @returns {int} 所在的页编号。
     */
    z: function(i){
        return Math.floor(this.checki(i) / this.p());
    },
    /**
     * 将i分解为一个包括页、行、列的对象。
     * @public
     * @function
     * @param {int} i 第i项，如果不传参数则默认为当前选中项。
     * @returns {object} m 格式为{x:a,y:b,z:c}的对象，其中a为列编号，b为所在页行编号，c为页编号
     */
    i2xyz: function(i){
        i = this.checki(i);
        return {
            x: this.il(i),
            y: this.yp(i),
            z: this.z(i)
        }
    },
    /**
     * 将i分解为一个包括行、列的对象。
     * @public
     * @function
     * @param {int} i 第i项，如果不传参数则默认为当前选中项。
     * @returns {object} m 格式为{x:a,y:b}的对象，其中a为列编号，b为所在行编号。
     */
    i2xy: function(i){
        i = this.checki(i);
        return {
            x: this.il(i),
            y: this.y(i)
        }
    },
    /**
     * 获取第i项所在的页的第一项的编号。
     * @public
     * @function
     * @param {int} i 第i项，如果不传参数则默认为当前选中项。
     * @returns {int} 所在的页的第一项的编号。
     */
    sp: function(i){
        i = this.checki(i);
        return i - this.ip(i);
    },
    /**
     * 获取第i项所在的页的最后一项的编号。
     * @public
     * @function
     * @param {int} i 第i项，如果不传参数则默认为当前选中项。
     * @returns {int} 所在的页的最后一项的编号。
     */
    ep: function(i){
		var r = this.sp(i)+ this.p() - 1
        return r >= this.length ? this.length - 1 : r;
    },
    /**
     * 获取第i项所在的行的第一项的编号。
     * @public
     * @function
     * @param {int} i 第i项，如果不传参数则默认为当前选中项。
     * @returns {int} 所在的行的第一项的编号。
     */
    sl: function(i){
        i = this.checki(i);
        return i - this.il(i);
    },
    
    
    
    
    /**
     * 打开这个menu,使其受到键盘控制,会触发onOpen事件。
     * @public
     * @function
     * @returns {boolean} 是否打开成功
     */
    open: function(){
        common.key.change(this);
        //触发onOpen
        this.onOpen && this.onOpen()
        this.checkCurrPage && this.checkCurrPage(function(){
			
		})
		return true;
    },    
    /**
     * 关闭这个menu,使其不受键盘控制,会触发onClose事件
     * @public
     * @function
     * @returns {boolean} 是否关闭成功
     */
    close: function(){
        common.key.unbind(this);
        //触发onClose
        this.onClose && this.onClose()
		return true;
    },
    /**
     * 菜单跳转到第i项。
     * @public
     * @function
     * @param {int} i 第i项。
     * @returns {boolean} 是否跳转成功
     */
    go: function(i){
        //common.log("移动光标到 " + i);
        if (typeof(i) === "number" && i >= 0 && i < this.length && this.i != i) {
            var p = this.i;
            this.i = i;
            //触发onLineChange
            if (this.i2xyz(p).z != this.i2xyz(i).z) {
				var self = this;
                this.checkCurrPage && this.checkCurrPage();
                this.onPageChange && this.onPageChange();
            }
            //触发onPageChange
            if (this.i2xy(p).y != this.i2xy(i).y) {
                this.onLineChange && this.onLineChange();
            }
            //触发onChange
            this.onChange && this.onChange();
            return true;
        }
        return false;
    },
    /**
     * 菜单按行列方式跳转
     * @public
     * @function
     * @param {objec} m 格式为{x:a,y:b}的对象，其中a为列编号，b为所在行编号。
     * @returns {boolean} 是否跳转成功
     */
    goxy: function(m){
        return this.go(this.xy2i(m));
    },
    /**
     * 菜单按页行列方式跳转
     * @public
     * @function
     * @param {object} m 格式为{x:a,y:b,z:c}的对象，其中a为列编号，b为所在页行编号，c为页编号
     * @returns {boolean} 是否跳转成功
     */
    goxyz: function(m){
        return this.go(this.xyz2i(m));
    },
    /**
     * 跳转到上一项
     * @public
     * @function
     * @returns {boolean} 是否跳转成功
     */
    prev: function(){
        return this.movex(-1);
    },
    /**
     * 跳转到下一项
     * @public
     * @function
     * @returns {boolean} 是否跳转成功
     */
    next: function(){
        return this.movex(1);
    },
    /**
     * 跳转到上一行
     * @public
     * @function
     * @returns {boolean} 是否跳转成功
     */
    prevLine: function(){
        return this.movey(-1);
    },
    /**
     * 跳转到下一行
     * @public
     * @function
     * @returns {boolean} 是否跳转成功
     */
    nextLine: function(){
        return this.movey(1);
    },
    /**
     * 跳转到上一页
     * @public
     * @function
     * @returns {boolean} 是否跳转成功
     */
    prevPage: function(){
        return this.movez(-1);
    },
    /**
     * 跳转到下一页
     * @public
     * @function
     * @returns {boolean} 是否跳转成功
     */
    nextPage: function(){
        return this.movez(1);
    },
    /**
     * 进入当前项
     * @public
     * @function
     * @returns {boolean} 是否跳转成功
     */
    enter: function(){
        this.onEnter && this.onEnter();
		return true;
    },
	
	
    /**
     * 菜单被打开，执行open方法时触发
	 * @event
     */
	onOpen: function(){},
    /**
     * 菜单被关闭，执行close方法时触发
	 * @event
     */
	onClose: function(){},
    /**
     * 进入菜单项，执行enter方法时触发（默认回车键触发）
	 * @event
     */
	onEnter: function(){},
    /**
     * 选中项改变时触发
	 * @event
     */
	onChange: function(){},
    /**
     * 选中项换行时触发
	 * @event
     */
	onLineChange: function(){},
    /**
     * 选中项换页时触发
	 * @event
     */
	onPageChange: function(){},
    /**
     * 菜单被open后，有按键时触发，传入按键码
	 * @event
     * @param {int} key 按键码
     */
	onKeyPress: function(){}
}
